﻿using System;
using UnityEngine;

namespace Gp.Scripts.Core
{
    public abstract class SmartValue<T>
    {
        protected event Action<T> ValueChangeEvent;

        public T Value
        {
            get => GetValue();
            set
            {
                var args = GetValue();
                SetValue(value);
                CommonUtils.SafeCall(() => ValueChangeEvent?.Invoke(args), "ValueChangeEvent",
                    "Error when setting value");
            }
        }


        protected abstract void SetValue(T value);
        protected abstract T GetValue();


        /// <summary>
        /// 事件参数为赋值之前的值。如需要赋值后的值，使用该类的 Value 属性
        /// </summary>
        public IDisposable Bind(Action<T> onValueChanged)
        {
            ValueChangeEvent += onValueChanged;
            return new EventDisposable(() => ValueChangeEvent -= onValueChanged);
        }

        public void UnBindAll()
        {
            ValueChangeEvent = null;
        }
    }


    /// 基本数值的包装类，可设置监听
    public class IntValue : SmartValue<int>
    {
        private int _value;
        private Func<int> _maxRange;
        private Func<int> _minRange;

        public IntValue(int min, int max)
        {
            _maxRange = () => int.MaxValue;
            _minRange = () => min;
        }
        

        public IntValue(int value, Func<int> minRange = null, Func<int> maxRange = null)
        {
            _maxRange = maxRange ?? (() => int.MaxValue);
            _minRange = minRange ?? (() => 0);
            Value     = value;
        }

        public IntValue()
        {
            _maxRange = () => int.MaxValue;
            _minRange = () => 0;
        }

        protected override void SetValue(int value)
        {
            int newValue = Mathf.Clamp(value, MinRange, MaxRange);
            _value = newValue;
        }

        protected override int GetValue()
        {
            _value = Mathf.Clamp(_value, MinRange, MaxRange);
            return _value;
        }


        public int MaxRange {
            get => _maxRange?.Invoke() ?? 0;
            set => _maxRange = () => value; 
        }

        public int MinRange
        {
            get => _minRange?.Invoke() ?? 0;
            set => _minRange = () => value;
        }


        public void SetMaxRangeFunc(Func<int> maxRange)
        {
            _maxRange = maxRange;
        }

        public void SetMinRangeFunc(Func<int> minRange)
        {
            _minRange = minRange;
        }

        public void ToMin()
        {
            Value = MinRange;
        }

        public void ToMax()
        {
            Value = MaxRange;
        }
    }
    
    
    public class FloatValue : SmartValue<float>
    {
        private float _value;
        private Func<float> _maxRange;
        private Func<float> _minRange;

        public FloatValue(float min, float max)
        {
            _maxRange = () => float.MaxValue;
            _minRange = () => min;
        }
        

        public FloatValue(float value, Func<float> minRange = null, Func<float> maxRange = null)
        {
            Value = value;
            _maxRange = maxRange ?? (() => float.MaxValue);
            _minRange = minRange ?? (() => 0);
        }

        public FloatValue()
        {
            _maxRange = () => float.MaxValue;
            _minRange = () => 0;
        }

        protected override void SetValue(float value)
        {
            float newValue = Mathf.Clamp(value, MinRange, MaxRange);
            _value = newValue;
        }

        protected override float GetValue()
        {
            _value = Mathf.Clamp(_value, MinRange, MaxRange);
            return _value;
        }


        public float MaxRange {
            get => _maxRange?.Invoke() ?? 0;
            set => _maxRange = () => value; 
        }

        public float MinRange
        {
            get => _minRange?.Invoke() ?? 0;
            set => _minRange = () => value;
        }


        public void SetMaxRangeFunc(Func<float> maxRange)
        {
            _maxRange = maxRange;
        }

        public void SetMinRangeFunc(Func<float> minRange)
        {
            _minRange = minRange;
        }
        
        public void ToMin()
        {
            Value = MinRange;
        }

        public void ToMax()
        {
            Value = MaxRange;
        }
    }


    public class StringValue : SmartValue<string>
    {
        private string _value;
        protected override void SetValue(string value)
        {
            _value = value;
        }

        protected override string GetValue()
        {
            return _value;
        }
    }
}